02A pairs experiments

Read the pairwise competitive outcomes determined by colony counting on TSA

The script below generates the table for manual keyin

if (FALSE) source("script/02A-pairs_experiment-01-pairwise_manual_key_in.R")

Then I manually checked the scanned plate images of competitive pairs. The plate images are saved in folder data/raw/plate_scan/emergent_coexistence_plate_scan/ divided according to the experimental batches.

Batch Community
B2 2.6, 2.8, 7.1, 8.4, 10.2, 11.1
C 11.1 isolate 1
C2 11.2
D 1.2, 1.4, 1.6, 1.7, 4.1, 11.5
# Read result colony counts and dilution factor
if (run_scripts) source("script/02A-pairs_experiment-02-colony_count.R")

There are 186x3=558 outcomes of pairwise competitions.

pairs_competition <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_competition.csv", col_types = cols())
pairs_competition

67 of of 558 pair-frequency without determined outcomes of pairwise competitions will be determined by using CASEU method

pairs_competition %>% filter(is.na(ColonyCount))

186 pair IDs saved in data/temp/pairs_ID.csv

pairs_ID <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_ID.csv", col_types = cols())
pairs_ID

Ambiguous pairs and isolates on TSA agar plates

if (run_scripts) source("script/02A-pairs_experiment-03-pairwise_ambiguous.R")

There are 67 pair-freqs that the competition outcome cannot be determined by TSA plate counting because of ambiguous morphology. The ambiguous pairs will be later examined by using selective media or Sanger sequencing.

pairs_ambiguous <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_ambiguous.csv", col_types = cols())
pairs_ambiguous

In total, 28 pairs

pairs_ambiguous %>% 
  group_by(Community, Isolate1, Isolate2) %>%
  summarize(Count = n(), .groups = "keep")

36 isolates involved in the ambiguous pairs.

isolates_ambiguous <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/isolates_ambiguous.csv", col_types = cols())
isolates_ambiguous

Map pairs and isolates to the DW96 plate layout

if (run_scripts) source("script/02A-pairs_experiment-04-pairwise_plate_layout.R")

Each plate has 96 rows and has the following variables

plates <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/plates.csv", col_types = cols())
plates

Plates for across-community and random assembly

plates_random <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/plates_random.csv", col_types = cols())
plates_random
plates_list <- plates %>%
    filter(Plate == "P1") %>%
    distinct(Batch, PlateLayout) %>%
    rename(batch = Batch, platelayout = PlateLayout) %>%
    rowwise() %>%
    mutate(plate = filter(plates, Batch == batch, PlateLayout == platelayout, Plate == "P1") %>% list) %>%
    mutate(plate = prepare_plate_draw(plate) %>% list) %>%
    mutate(p_plate = draw_plate_from_df(plate) %>% list) 

plot_grid(plotlist = plates_list$p_plate, labels = paste0(plates_list$batch, " ", plates_list$platelayout),
          ncol = 2)
Warning: Removed 2 rows containing missing values (geom_text).

Plate layout that takes different initial frequencies:

  • P1 is 50%:50%.

  • P2 and P3 are identical and whose rows are 95% and columns are 5%.

The only exception is plate C11R1 in batch C, which only has one plate.

OD <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/OD.csv", col_types = cols())

OD %>%
    filter(Community == "C1R2", Wavelength == 620) %>%
    ggplot(aes(x = Transfer, y = Abs, color = Isolate1Freq)) +
    geom_line() + geom_point() +
    facet_grid(Isolate1 ~ Isolate2) +
    theme_classic()

NA

02B CASEU sanger sequencing

list.files(here::here("output/protocol"), pattern = "caseu")
devtools::install_bitbucket('dattamanoshi/caseu') # Install CASEU package
library(CASEU)

Test on example data

if (run_scripts) source("script/02B-CASEU_sanger_seq-00-test.R")

CASEU pilot1

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf.

read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot1/protocol_20190813_Sanger_seq_prep-genewiz_table.csv", col_types = cols())

The isolates used in this round is from the list below.

isolates
Isolate Code Taxa
C11R1 isolate 1 A Pseudomonas
C1R7 isolate 2 B Pseudomonas
C1R7 isolate 1 C Enterobacter
C1R7 isolate 7 D Raoultella

Read trace matrices for isolates and mixtures

if (run_scripts) source("script/02B-CASEU_sanger_seq-01-pilot1.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot1.csv", col_types = cols())

CASEU pilot2

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190813_Sanger_seq_prep.pdf. There are 32 samples from pairwise competition and 16 samples from control. Also read Sylvie’s data.

read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot2/protocol_20190910_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())

Isolates A B C D in control are the isolates below.

Isolate Code Taxa
C11R1 isolate 1 A Pseudomonas
C1R7 isolate 2 B Pseudomonas
C1R7 isolate 1 C Enterobacter
C1R7 isolate 7 D Raoultella
if (run_scripts) source("script/02B-CASEU_sanger_seq-02-pilot2.R")
#source("script/02B-CASEU_sanger_seq-02a-pilot2_Sylvie.R") # Run Sylvie's sequence

In the 12 control synthetic pairs that were made of 4 isolates, compare these pairs’ OD frequencies, colony counts, and CASEU predictions.

Read CASEU predicted frequencies and colony count frequencies in the 12 control pairs.

CASEU_pilot2 <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot2.csv", col_types = cols())
CASEU_pilot2_plating <- read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot2/CASEU_pilot2_plating.csv", col_types = cols()) %>%
  mutate(Isolate1ColonyFreq = Isolate1Colony / (Isolate1Colony + Isolate2Colony),
    Isolate2ColonyFreq = Isolate2Colony / (Isolate1Colony + Isolate2Colony))
CASEU_pilot2

CASEU pilot3

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20190923_SequalPrep_Sanger_prep.pdf.

read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot3/protocol_20190924_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())

Read trace matrices for isolates and mixtures

# It takes about ~15 mins to run 
if (run_scripts) source("script/02B-CASEU_sanger_seq-03-pilot3.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot3.csv", col_types = cols())

CASEU pilot4

The plate layout of PCR plate and list of samples are specified in output/protocol/protocol_20191007_Sanger_seq_prep.pdf.

read_csv("~/Dropbox/lab/emergent-coexistence/data/raw/Sanger/CASEU_pilot4/protocol_20191007_Sanger_seq_prep-genewiz_table_CYC.csv", col_types = cols())

Read trace matrices for isolates and mixtures

# It takes about ~15 mins to run
if (run_scripts) source("script/02B-CASEU_sanger_seq-04-pilot4.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_pilot4.csv", col_types = cols())

CASEU six plates

  • Genewiz submission code: CASEU_RN_5 (which is not correct because these are not RN plates)
  • Plates:
    • B2 T7 933 P2
    • B2 T7 444 P2
    • C2 T7 13A P2
    • C2 T7 13B P2
    • D T7 75 P2
    • D T7 5543 P2
  • Notes: the plates must be placed in order!!
# Generate sequencing csv
if (FALSE) {
genewiz_table <- tibble(Sample = 1:(96*6), 
       `DNA Name` = paste0(rep(c("B2_T7_933_P2", "B2_T7_444_P2", "C2_T7_13A_P2", "C2_T7_13B_P2",  "D_T7_75_P2", "D_T7_5543_P2"), each = 96), "_", rep(1:96, 6)), 
       `Length (bp)` = 1000, `Concentration (ng/uL)` = 0.83, Primer = "27F")

write_csv(genewiz_table, here::here("output/protocol/tab_fig/20211202_Sanger_seq_prep-genewiz_table_CYC.csv"))

}
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_sixplates.csv", col_types = cols())

Random network, CASEU batch 1

  • Genewiz submisstion code: Caseu_RN_1
  • Plate layout: T3 C P2
  • Description: samples 3, 4, 5, 12, 13, 27, 29, 33, 73, 85, 86, 91, and 94 (order by column in the plate layout) arrived Genewiz dry, so they are not processed.
# If will take ~2 hr to run
if (run_scripts) source("script/02B-random_network_CASEU-01-batch1.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN1.csv", col_types = cols())

Random network, CASEU batch 2

  • Genewiz submission code: Caseu_RN_2
  • Plate layout: T3 C P2
  • Description: this plate layout contains the isolates for all 4 random assembled communities
# It takes ~30 mins
if (run_scripts) source("script/02B-random_network_CASEU-02-batch2.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN2.csv", col_types = cols())

Random network, CASEU batch 3

  • Genewiz submisstion code: Caseu_RN_3
  • Plate layout:
    • P1 (T0 C P2), tracking number 30-333649143
    • P2 (T0 AD P2), tracking number 30-333649365
    • P3 (T3 AD P2), tracking number 30-333649517
  • Description: AD plates have the isolates assembled from the self-assembled communities but different communities
# It takes ~1.5 hr
if (run_scripts) source("script/02B-random_network_CASEU-03-batch3.R")

Use T0 OD frequencies

read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN3.csv", col_types = cols())

Random network, CASEU batch 4

  • Genewiz submisstion code: Caseu_RN_4
  • Plate layout: T3 BD P3
  • Description: This plate has the full AcrAss2 (B) and half of RanAss2 (D) network.
if (run_scripts) source("script/02B-random_network_CASEU-04-batch4.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/CASEU_RN4.csv", col_types = cols())

02C pairs_OD_CFU

General formula of error propagation

This section explains the error propagation theory to estimate the uncertainty in the experimental measurement. There are one or more quantities \(x, y, ...\), with corresponding uncertainties \(\delta x, \delta y, ...\) and that we wish to use the measured values of x and y to calculate the quantity of real interest q. There are three provisional rules:

  1. The square-root rule for counting experiments. The average number of event in time T is \(v\pm\sqrt{v}\)

  2. Uncertainty in sums and differences. The computed mean value \(q=x+y+z-(u+w)\). If the uncertainties in x, …, w are known to be independent and random, then the uncertainty in the computed value of q is the quadratic sum \(\delta q = \sqrt{(\delta x)^2+(\delta y)^2+(\delta z)^2+(\delta u)^2+(\delta w)^2}\) , In any case, \(\delta q\) is never larger than their ordinary sum \(\delta q \leqslant \delta x + \delta y+ \delta z + \delta u + \delta w\)

  3. Uncertainty in product and quotients. \(q=\frac{x\times z}{u\times w}\), then the fractional uncertainty in the computed value q is the sum. If the uncertainties in x, …,w are independent and random, then the fractional uncertainty in q is the sum in quadrature of the original uncertainties, \(\frac{\delta q}{\left|q\right|} = \sqrt{(\frac{\delta x}{\left|x\right|})^2 + \frac{\delta y}{\left|y\right|})^2 +\frac{\delta z}{\left|z\right|})^2 +\frac{\delta u}{\left|u\right|})^2 + \frac{\delta w}{\left|w\right|})^2}\). \(\frac{\delta q}{\left| q \right|} \leqslant \frac{\delta x}{\left| x \right|} + \frac{\delta z}{\left| z \right|} + \frac{\delta u}{\left| u \right|} + \frac{\delta w}{\left| w \right|}\)

Taking these three provisional rules together, the general formula for error propagation takes the following form. Assume the computed quantity is a function of \(x_1, x_2, ..., x_n\), the uncertainty in q is \[\delta q= \sqrt{(\sum{\frac{\partial q}{\partial x_i}}\delta x_i)^2}\]

Uncertainty in epsilon

if (run_scripts) source("script/02C-pairs_OD_CFU-01-epsilon_uncertainty.R")

The uncertainties in each isolate’ epsilon \(\epsilon_A = \frac{OD_A DF_A v_A}{CFU_A}\) comes from four parts:

  1. \(DF\): Dilution factors. The uncertainty comes from the pipetting in serial dilution, which is calcaulted below.
  2. \(v\): Plating volumes. The systematic error for P20 set at 20 uL is 0.4 uL.
  3. \(CFU\): CFU counts. The uncertainty in CFU follows poisson distribution, which means that the variance is the same as the mean (measured CFU). The standard deviation is \(\sqrt{CFU}\).
  4. \(OD\): OD measurement. The uncertainty in measuring OD in plate reader, which is assumed to be 0.001.

Dilution factor

The uncertainty in dilution factor comes from the pipetting steps in serial dilution, which include two pipetting volumes:

  1. V1: serial dispensing 10 uL of diluted solution using mP20. It has uncertainty ErrorV1 2 uL.
  2. V2: dispense 90 uL of PBS using mP200. It has uncertainty ErrorV2 0.4 uL.

For dilution factor \(10^{n}\), it has the the mean \((\frac{V_1}{V_1+V_2})^n\). To obtain the uncertainty in the measured mean, first we caluculate the partial derivatives \(\frac{\partial DF}{\partial V_1}\) and \(\frac{\partial DF}{\partial V_2}\). Then the uncertainty \(\delta DF = \sqrt{(\frac{\partial DF}{\partial V_1}\delta V_1)^2 + (\frac{\partial DF}{\partial V_2}\delta V_2)^2}\)

dilution_factor <- tibble(n = c(4, 5), V1 = 10, V2 = 90, ErrorV1 = 0.4, ErrorV2 = 2) %>%
  mutate(PartialV1 = n * V1^(n-1) * V2 / (V1+V2)^(n+1), #-n*(V1+V2)^(n-1)*V2/(V1^(n+1)),
         PartialV2 = -n * V1^(n-1) / (V1+V2)^(n+1), #n*(V1+V2)^(n-1)/(V1^n),
         DF = (V1/(V1+V2))^n,
         ErrorDF = sqrt((PartialV1*ErrorV1)^2 + (PartialV2*ErrorV2)^2))

dilution_factor

By using error propagation theroy, the uncertainty in isolates epsilon has the form

\[\delta \epsilon = \sqrt{(\frac{\partial \epsilon}{\partial DF}\delta DF)^2 +(\frac{\partial \epsilon}{\partial CFU}\delta CFU)^2 + (\frac{\partial \epsilon}{\partial OD}\delta OD)^2 + (\frac{\partial \epsilon}{\partial V}\delta V)^2}\]

isolates_epsilon_uncertainty <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/isolates_epsilon_uncertainty.csv", col_types = cols())
isolates_epsilon_uncertainty
NA

There are 7 isolates that have either 0 CFU or negative OD value, so they don’t have epsilon values.

isolates_epsilon_uncertainty %>%
  filter(is.na(Epsilon))

Convert T0 OD frequencies to CFU frequencies

if (run_scripts) source("script/02C-pairs_OD_CFU-02-CFU_frequency.R")

The outcome of pairwise competition were determined by comparing the frequency changes between T0 and T8. The T8 frequencies were determined by plating the mature media on rich agar media on which the colonies were counted, whereas T0 frequencies were set to 95/5, 50/50 and 5/95 by mixing two isolate inocula with equal OD. In this section, I will use the OD-CFU conversion coefficient \(\epsilon\) derived from T8 isolate data to convert T0 OD frequencies into CFU frequencies. In specific, the CFU frequency of isolate 1 \(f^C_1\) of a pair can be derived from OD frequencies of isolate 1 and 2 \(f^O_1 ,f^O_2\), which have the relationship below.

\(f^C_1 = \frac{f^o_1\epsilon_1DFv}{f^o_1\epsilon_1DFv + f^o_2\epsilon_2DFv}=\frac{f^o_1\epsilon_1}{f^o_1\epsilon_1 + f^o_2\epsilon_2}\)

where \(\epsilon\) of each isolate was pre-calculated from T8 dataset. DF and v are the same in conversion.

read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_CFU_freq.csv", col_types = cols())

Uncertainty in T0 CFU frequencies

if (run_scripts) source("script/02C-pairs_OD_CFU-03-CFU_frequency_uncertainty.R")

Write CFU frequencies to data/temp/pairs_CFU_freq_uncertainty.csv

read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_CFU_freq_uncertainty.csv", col_types = cols())

02D determine pairwise interaction

Combine outcomes of pairwise competition from CFU counts and CASEU

Raw data (e.g., CFU counts and CASEU Sanger sequences) are processed and generated into temporary result csv:

  1. 02B-CASEU_sanger_seq reads CASEU raw data and outputs temp/CASEU_pilot2.csv and temp/CASEU_pilot3.csv. Both files are CASEU predicted T8 frequencies.

  2. 02C-pairs_OD_CFU reads pair_competition and dilution factor data, and it outputs temp/pairs_CFU_freq_uncertainty.csv, which has the T0 OD-converted CFU frequencies and T8 CFU frequencies with uncertainties.

if (run_scripts) source("script/02D-determine_pairwise_interaction-01-combine_CFU_CASEU_result.R")

The script in this section returns a data.frame pairs_freq that has the following variables:

  • Community
  • Isolate1 and Isolate2: indices of isolates within a community. The number of isolate1 is always smaller than isolate2
  • Isolate1InitialODFreq and Isolate2InitialODFreq: 5, 50 or 95. The initial OD frequencies of isolates at T0. This two serve as discrete grouping variables.
  • Time: T0 or T8.
  • Isolate1MeasuredFreq: the measured frequency od isolate1 in the pair.
  • ErrorIsolate1MeasuredFreq: the uncertainty of Isolate1MeasuredFreq.
  • RawDataType: OD, ODtoCFU, CFU, Sanger (CASEU). The raw data type in which the isolate frequencies were measured.
  • Contamination: logical. There are contamination in three pairs at T8 plates.

186x3x2=1116 pair-freq at two time points for the self-assembled community networks.

read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_freq.csv", col_types = cols())

Determine pairwise interactions

if (run_scripts) source("script/02D-determine_pairwise_interaction-02-determine_pairwise_interaction.R")

Table of all 27 + 4 possible combinations of fitness function and their interaction types

read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_interaction_table.csv", col_types = cols())

Table of interaction types

pairs_interaction_fitness <- read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_interaction_fitness.csv", col_types = cols())
pairs_interaction_fitness %>%
  group_by(Set, InteractionType) %>%
  summarize(Count = n(), .groups = "keep") 

Isolate tournament

if (run_scripts) source("script/02D-determine_pairwise_interaction-03-isolate_tournament.R")

Tournament ranks of each isolate. Note that I consider neturality and bistability as draw in the tournament.

  • Score: the competitive scores of isolate. This score is computed by the formula: number of wins - number of loses + 0 * number of draws.
  • Game: number of pairwise competition the isolate has played. The number of games an isolate plated within a community should be community size minus one.
  • Rank: the ranks based on Score. The ranks range from 1 to the focal community size. Isolates with the same scores in a community are given the same rank.
  • PlotRank: continuous rank for plotting convenience.

02E competition phylogeny

Isolates’ RDP taxonomy

if (run_scripts) source("script/02E-competition_phylogeny-01-pairs_taxonomy.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_taxonomy.csv", col_types = cols())

Isolates’ 16S sequence difference

if (run_scripts) source("script/02E-competition_phylogeny-02-pairs_16S.R")
read_csv("~/Dropbox/lab/emergent-coexistence/data/temp/pairs_16S.csv", col_types = cols())

Summary

Read and combine pairs data

if (run_scripts) source("script/02-pairs-01-read_data.R")

186 pairs of self-assembled communities and 112 pair from across-community and random networks

Pairs with three initial frequencies and three. 186x3x2=1116

pairs_meta contains the growth traits of isolates. Note that the order of Isolate1 and Isolate2 in some pairs are flipped such that Isolate1 is always the dominant strain and Isolate 2 is the subdomaint one. Dominant strain is the winner in exclusion pairs, and the more abundant strain (50:50 treatment) in coexistence pairs.

if (FALSE) pairs_meta <- read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_meta.csv", col_types = cols())

Example outcome types

if (run_scripts) source("script/02-pairs-02-outcome_types.R")

Coarse-grained

Fine-grained

read_csv("~/Dropbox/lab/emergent-coexistence/data/output/pairs_example_outcomes_finer.csv", col_types = cols())
LS0tCnRpdGxlOiAiQW5hbHlzaXMgb24gcGFpcndpc2UgY29tcGV0aXRpb24gYXNzYXlzIgphdXRob3I6ICJDaGFuZy1ZdSBDaGFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgZWNobyA9IFRSVUUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGNvd3Bsb3QpCnNvdXJjZShoZXJlOjpoZXJlKCJwbG90dGluZ19zY3JpcHRzL21pc2MuUiIpKQpydW5fc2NyaXB0cyA8LSBGCmBgYAoKCiMgMDJBIHBhaXJzIGV4cGVyaW1lbnRzCgotIEV4cGVyaW1lbnQtcmVsYXRlZCBzY3JpcHRzCgotIFJlYWQgcGFpcndpc2UgY29tcGV0aXRpb24gb3V0Y29tZXMgdGhhdCBhcmUgZGV0ZXJtaW5lZCBieSBjb2xvbnkgY291bnRzIG9uIHBsYXRlcy4gCgotIFJlYWQgQ0FTRVUgcmVzdWx0cwoKLSBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSA5Ni13ZWxsIHBsYXRlIGxheW91dAoKCiMjIFJlYWQgdGhlIHBhaXJ3aXNlIGNvbXBldGl0aXZlIG91dGNvbWVzIGRldGVybWluZWQgYnkgY29sb255IGNvdW50aW5nIG9uIFRTQQoKVGhlIHNjcmlwdCBiZWxvdyBnZW5lcmF0ZXMgdGhlIHRhYmxlIGZvciBtYW51YWwga2V5aW4KCmBgYHtyfQppZiAoRkFMU0UpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAxLXBhaXJ3aXNlX21hbnVhbF9rZXlfaW4uUiIpCmBgYAoKVGhlbiBJIG1hbnVhbGx5IGNoZWNrZWQgdGhlIHNjYW5uZWQgcGxhdGUgaW1hZ2VzIG9mIGNvbXBldGl0aXZlIHBhaXJzLiBUaGUgcGxhdGUgaW1hZ2VzIGFyZSBzYXZlZCBpbiBmb2xkZXIgYGRhdGEvcmF3L3BsYXRlX3NjYW4vZW1lcmdlbnRfY29leGlzdGVuY2VfcGxhdGVfc2Nhbi9gIGRpdmlkZWQgYWNjb3JkaW5nIHRvIHRoZSBleHBlcmltZW50YWwgYmF0Y2hlcy4KCkJhdGNoIHwgQ29tbXVuaXR5Ci0tLS0tLXwtLS0tLS0tLS0tLQpCMiAgICB8IDIuNiwgMi44LCA3LjEsIDguNCwgMTAuMiwgMTEuMQpDICAgICB8IDExLjEgaXNvbGF0ZSAxCkMyICAgIHwgMTEuMgpEICAgICB8IDEuMiwgMS40LCAxLjYsIDEuNywgNC4xLCAxMS41CgoKYGBgIHtyfQojIFJlYWQgcmVzdWx0IGNvbG9ueSBjb3VudHMgYW5kIGRpbHV0aW9uIGZhY3RvcgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQS1wYWlyc19leHBlcmltZW50LTAyLWNvbG9ueV9jb3VudC5SIikKYGBgCgpUaGVyZSBhcmUgMTg2eDM9NTU4IG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9ucy4KCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfY29tcGV0aXRpb24uY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwYWlyc19jb21wZXRpdGlvbgpgYGAKCjY3IG9mIG9mIDU1OCBwYWlyLWZyZXF1ZW5jeSB3aXRob3V0IGRldGVybWluZWQgb3V0Y29tZXMgb2YgcGFpcndpc2UgY29tcGV0aXRpb25zIHdpbGwgYmUgZGV0ZXJtaW5lZCBieSB1c2luZyBDQVNFVSBtZXRob2QKCmBgYHtyfQpwYWlyc19jb21wZXRpdGlvbiAlPiUgZmlsdGVyKGlzLm5hKENvbG9ueUNvdW50KSkKYGBgCgoxODYgcGFpciBJRHMgc2F2ZWQgaW4gYGRhdGEvdGVtcC9wYWlyc19JRC5jc3ZgCgpgYGB7cn0KcGFpcnNfSUQgPC0gcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX0lELmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfSUQKYGBgCgoKCiMjIEFtYmlndW91cyBwYWlycyBhbmQgaXNvbGF0ZXMgb24gVFNBIGFnYXIgcGxhdGVzCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkEtcGFpcnNfZXhwZXJpbWVudC0wMy1wYWlyd2lzZV9hbWJpZ3VvdXMuUiIpCmBgYAoKClRoZXJlIGFyZSA2NyBwYWlyLWZyZXFzIHRoYXQgdGhlIGNvbXBldGl0aW9uIG91dGNvbWUgY2Fubm90IGJlIGRldGVybWluZWQgYnkgVFNBIHBsYXRlIGNvdW50aW5nIGJlY2F1c2Ugb2YgYW1iaWd1b3VzIG1vcnBob2xvZ3kuIFRoZSBhbWJpZ3VvdXMgcGFpcnMgd2lsbCBiZSBsYXRlciBleGFtaW5lZCBieSB1c2luZyBzZWxlY3RpdmUgbWVkaWEgb3IgU2FuZ2VyIHNlcXVlbmNpbmcuIAoKYGBge3J9CnBhaXJzX2FtYmlndW91cyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfYW1iaWd1b3VzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfYW1iaWd1b3VzCmBgYAoKSW4gdG90YWwsIDI4IHBhaXJzCgpgYGB7cn0KcGFpcnNfYW1iaWd1b3VzICU+JSAKICBncm91cF9ieShDb21tdW5pdHksIElzb2xhdGUxLCBJc29sYXRlMikgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpLCAuZ3JvdXBzID0gImtlZXAiKQpgYGAKCjM2IGlzb2xhdGVzIGludm9sdmVkIGluIHRoZSBhbWJpZ3VvdXMgcGFpcnMuIAoKYGBge3J9Cmlzb2xhdGVzX2FtYmlndW91cyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvaXNvbGF0ZXNfYW1iaWd1b3VzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKaXNvbGF0ZXNfYW1iaWd1b3VzCmBgYAoKCgojIyBNYXAgcGFpcnMgYW5kIGlzb2xhdGVzIHRvIHRoZSBEVzk2IHBsYXRlIGxheW91dAoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJBLXBhaXJzX2V4cGVyaW1lbnQtMDQtcGFpcndpc2VfcGxhdGVfbGF5b3V0LlIiKQpgYGAKCkVhY2ggcGxhdGUgaGFzIDk2IHJvd3MgYW5kIGhhcyB0aGUgZm9sbG93aW5nIHZhcmlhYmxlcwoKYGBge3J9CnBsYXRlcyA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL291dHB1dC9wbGF0ZXMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwbGF0ZXMKYGBgCgoKUGxhdGVzIGZvciBhY3Jvc3MtY29tbXVuaXR5IGFuZCByYW5kb20gYXNzZW1ibHkKCmBgYHtyfQpwbGF0ZXNfcmFuZG9tIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BsYXRlc19yYW5kb20uY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpwbGF0ZXNfcmFuZG9tCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gM30KcGxhdGVzX2xpc3QgPC0gcGxhdGVzICU+JQogICAgZmlsdGVyKFBsYXRlID09ICJQMSIpICU+JQogICAgZGlzdGluY3QoQmF0Y2gsIFBsYXRlTGF5b3V0KSAlPiUKICAgIHJlbmFtZShiYXRjaCA9IEJhdGNoLCBwbGF0ZWxheW91dCA9IFBsYXRlTGF5b3V0KSAlPiUKICAgIHJvd3dpc2UoKSAlPiUKICAgIG11dGF0ZShwbGF0ZSA9IGZpbHRlcihwbGF0ZXMsIEJhdGNoID09IGJhdGNoLCBQbGF0ZUxheW91dCA9PSBwbGF0ZWxheW91dCwgUGxhdGUgPT0gIlAxIikgJT4lIGxpc3QpICU+JQogICAgbXV0YXRlKHBsYXRlID0gcHJlcGFyZV9wbGF0ZV9kcmF3KHBsYXRlKSAlPiUgbGlzdCkgJT4lCiAgICBtdXRhdGUocF9wbGF0ZSA9IGRyYXdfcGxhdGVfZnJvbV9kZihwbGF0ZSkgJT4lIGxpc3QpIAoKcGxvdF9ncmlkKHBsb3RsaXN0ID0gcGxhdGVzX2xpc3QkcF9wbGF0ZSwgbGFiZWxzID0gcGFzdGUwKHBsYXRlc19saXN0JGJhdGNoLCAiICIsIHBsYXRlc19saXN0JHBsYXRlbGF5b3V0KSwKICAgICAgICAgIG5jb2wgPSAyKQoKYGBgCgpQbGF0ZSBsYXlvdXQgdGhhdCB0YWtlcyBkaWZmZXJlbnQgaW5pdGlhbCBmcmVxdWVuY2llczoKCi0gUDEgaXMgNTAlOjUwJS4KCi0gUDIgYW5kIFAzIGFyZSBpZGVudGljYWwgYW5kIHdob3NlIHJvd3MgYXJlIDk1JSBhbmQgY29sdW1ucyBhcmUgNSUuCgpUaGUgb25seSBleGNlcHRpb24gaXMgcGxhdGUgQzExUjEgaW4gYmF0Y2ggQywgd2hpY2ggb25seSBoYXMgb25lIHBsYXRlLgoKYGBge3J9Ck9EIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9PRC5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCgpPRCAlPiUKICAgIGZpbHRlcihDb21tdW5pdHkgPT0gIkMxUjIiLCBXYXZlbGVuZ3RoID09IDYyMCkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBUcmFuc2ZlciwgeSA9IEFicywgY29sb3IgPSBJc29sYXRlMUZyZXEpKSArCiAgICBnZW9tX2xpbmUoKSArIGdlb21fcG9pbnQoKSArCiAgICBmYWNldF9ncmlkKElzb2xhdGUxIH4gSXNvbGF0ZTIpICsKICAgIHRoZW1lX2NsYXNzaWMoKQogICAgCmBgYAoKCgojIDAyQiBDQVNFVSBzYW5nZXIgc2VxdWVuY2luZwoKLSBUbyBkZXRlcm1pbmUgdGhlIHJlbGF0aXZlIGFidW5kYW5jZSBvZiBvZiBhbWJpZ3VvdXMgcGFpcnMgaW4gY29tcGV0aXRpdmUgYXNzYXlzLiAKCi0gVXNlIENBU0VVIHBhY2thZ2VzIHRvIGFuYWx5c2UgdGhlIFNhbmdlciBzZXF1ZW5jaW5nIG9mIG1peHR1cmUgY3VsdHVyZS4KCi0gU2FuZ2VyIHNlcXVlbmNpbmcgcHJvdG9jb2wgcHJlcGFyYXRpb24uIEV4cGVyaW1lbnRhbCBwcm90b2NvbCBmaWxlcyBhcmUgc2F2ZWQgaW4gZm9sZGVyIGBvdXRwdXQvcHJvdG9jb2wvYAoKYGBge3J9Cmxpc3QuZmlsZXMoaGVyZTo6aGVyZSgib3V0cHV0L3Byb3RvY29sIiksIHBhdHRlcm4gPSAiY2FzZXUiKQpgYGAKCi0gT25jZSB3ZSBnb3QgdGhlIG1peHR1cmUgU2FuZ2VyIHNlcXVlbmNlcyBiYWNrLCB3ZSBpbXBsZW1lbnQgYW5hbHlzaXMgYnkgdXNpbmcgYENBU0VVYCAoQ29tcG9zaXRpb25hbCBhbmFseXNpcyBieSBTYW5nZXIgZWxlY3Ryb3BoZXJvZ3JhbSB1bm1peGluZyksIGFuIFIgcGFja2FnZSBkZXNpZ25lZCBmb3IgcXVhbnRpZnlpbmcgcmVsYXRpdmUgYWJ1bmRhbmNlIG9mIFNhbmdlciBzZXF1ZW5jZXMgbWl4dHVyZS4gW3NvdXJjZSBjb2RlXShodHRwczovL2JpdGJ1Y2tldC5vcmcvRGF0dGFNYW5vc2hpL2Nhc2V1KS4gSW5zdGFsbCBgQ0FTRVVgIGZyb20gYml0YnVja2V0LgoKLSBDaGVjayBvdXQgW3BhY2thZ2UgdmlnbmV0dGVdKGh0dHBzOi8vaHRtbHByZXZpZXcuZ2l0aHViLmlvLz9odHRwczovL2JpdGJ1Y2tldC5vcmcvZGF0dGFtYW5vc2hpL2Nhc2V1L3Jhdy9tYXN0ZXIvZG9jL0NBU0VVX1ZpZ25ldHRlLmh0bWwpLgoKYGBge3IsIGVjaG8gPSBUUlVFLCBldmFsID0gRkFMU0V9CmRldnRvb2xzOjppbnN0YWxsX2JpdGJ1Y2tldCgnZGF0dGFtYW5vc2hpL2Nhc2V1JykgIyBJbnN0YWxsIENBU0VVIHBhY2thZ2UKbGlicmFyeShDQVNFVSkKYGBgCgoKIyMgVGVzdCBvbiBleGFtcGxlIGRhdGEKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAwLXRlc3QuUiIpCmBgYAoKCiMjIENBU0VVIHBpbG90MQoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDEvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGUuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClRoZSBpc29sYXRlcyB1c2VkIGluIHRoaXMgcm91bmQgaXMgZnJvbSB0aGUgbGlzdCBiZWxvdy4KCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQpUYWJsZTogaXNvbGF0ZXMKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDEtcGlsb3QxLlIiKQpgYGAKCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90MS5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCiMjIENBU0VVIHBpbG90MgoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTA4MTNfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIFRoZXJlIGFyZSAzMiBzYW1wbGVzIGZyb20gcGFpcndpc2UgY29tcGV0aXRpb24gYW5kIDE2IHNhbXBsZXMgZnJvbSBjb250cm9sLiBBbHNvIHJlYWQgU3lsdmllJ3MgZGF0YS4gCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9yYXcvU2FuZ2VyL0NBU0VVX3BpbG90Mi9wcm90b2NvbF8yMDE5MDkxMF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCklzb2xhdGVzIEEgQiBDIEQgaW4gY29udHJvbCBhcmUgdGhlIGlzb2xhdGVzIGJlbG93LiAKCklzb2xhdGUgICAgICAgICB8ICBDb2RlICAgICB8ICBUYXhhCi0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS18LS0tLS0tLQpDMTFSMSBpc29sYXRlIDEgfCBBICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMiAgfCBCICAgICAgICAgfCBQc2V1ZG9tb25hcwpDMVI3IGlzb2xhdGUgMSAgfCBDICAgICAgICAgfCBFbnRlcm9iYWN0ZXIKQzFSNyBpc29sYXRlIDcgIHwgRCAgICAgICAgIHwgUmFvdWx0ZWxsYQoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDItcGlsb3QyLlIiKQojc291cmNlKCJzY3JpcHQvMDJCLUNBU0VVX3Nhbmdlcl9zZXEtMDJhLXBpbG90Ml9TeWx2aWUuUiIpICMgUnVuIFN5bHZpZSdzIHNlcXVlbmNlCmBgYAoKCkluIHRoZSAxMiBjb250cm9sIHN5bnRoZXRpYyBwYWlycyB0aGF0IHdlcmUgbWFkZSBvZiA0IGlzb2xhdGVzLCBjb21wYXJlIHRoZXNlIHBhaXJzJyBPRCBmcmVxdWVuY2llcywgY29sb255IGNvdW50cywgYW5kIENBU0VVIHByZWRpY3Rpb25zLgoKUmVhZCBDQVNFVSBwcmVkaWN0ZWQgZnJlcXVlbmNpZXMgYW5kIGNvbG9ueSBjb3VudCBmcmVxdWVuY2llcyBpbiB0aGUgMTIgY29udHJvbCBwYWlycy4KCmBgYHtyfQpDQVNFVV9waWxvdDIgPC0gcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90Mi5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCkNBU0VVX3BpbG90Ml9wbGF0aW5nIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDIvQ0FTRVVfcGlsb3QyX3BsYXRpbmcuY3N2IiwgY29sX3R5cGVzID0gY29scygpKSAlPiUKICBtdXRhdGUoSXNvbGF0ZTFDb2xvbnlGcmVxID0gSXNvbGF0ZTFDb2xvbnkgLyAoSXNvbGF0ZTFDb2xvbnkgKyBJc29sYXRlMkNvbG9ueSksCiAgICBJc29sYXRlMkNvbG9ueUZyZXEgPSBJc29sYXRlMkNvbG9ueSAvIChJc29sYXRlMUNvbG9ueSArIElzb2xhdGUyQ29sb255KSkKQ0FTRVVfcGlsb3QyCmBgYAoKCgojIyBDQVNFVSBwaWxvdDMKClRoZSBwbGF0ZSBsYXlvdXQgb2YgUENSIHBsYXRlIGFuZCBsaXN0IG9mIHNhbXBsZXMgYXJlIHNwZWNpZmllZCBpbiBgb3V0cHV0L3Byb3RvY29sL3Byb3RvY29sXzIwMTkwOTIzX1NlcXVhbFByZXBfU2FuZ2VyX3ByZXAucGRmYC4gCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9yYXcvU2FuZ2VyL0NBU0VVX3BpbG90My9wcm90b2NvbF8yMDE5MDkyNF9TYW5nZXJfc2VxX3ByZXAtZ2VuZXdpel90YWJsZV9DWUMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClJlYWQgdHJhY2UgbWF0cmljZXMgZm9yIGlzb2xhdGVzIGFuZCBtaXh0dXJlcwoKYGBge3J9CiMgSXQgdGFrZXMgYWJvdXQgfjE1IG1pbnMgdG8gcnVuIAppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTAzLXBpbG90My5SIikKYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3BpbG90My5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCiMjIENBU0VVIHBpbG90NAoKVGhlIHBsYXRlIGxheW91dCBvZiBQQ1IgcGxhdGUgYW5kIGxpc3Qgb2Ygc2FtcGxlcyBhcmUgc3BlY2lmaWVkIGluIGBvdXRwdXQvcHJvdG9jb2wvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLnBkZmAuIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvcmF3L1Nhbmdlci9DQVNFVV9waWxvdDQvcHJvdG9jb2xfMjAxOTEwMDdfU2FuZ2VyX3NlcV9wcmVwLWdlbmV3aXpfdGFibGVfQ1lDLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgpSZWFkIHRyYWNlIG1hdHJpY2VzIGZvciBpc29sYXRlcyBhbmQgbWl4dHVyZXMKCmBgYHtyfQojIEl0IHRha2VzIGFib3V0IH4xNSBtaW5zIHRvIHJ1bgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1DQVNFVV9zYW5nZXJfc2VxLTA0LXBpbG90NC5SIikKYGBgCgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9waWxvdDQuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgojIyBDQVNFVSBzaXggcGxhdGVzCgotIEdlbmV3aXogc3VibWlzc2lvbiBjb2RlOiBDQVNFVV9STl81ICh3aGljaCBpcyBub3QgY29ycmVjdCBiZWNhdXNlIHRoZXNlIGFyZSBub3QgUk4gcGxhdGVzKQotIFBsYXRlczoKICAgIC0gQjIgVDcgOTMzIFAyCiAgICAtIEIyIFQ3IDQ0NCBQMgogICAgLSBDMiBUNyAxM0EgUDIKICAgIC0gQzIgVDcgMTNCIFAyCiAgICAtIEQgVDcgNzUgUDIKICAgIC0gRCBUNyA1NTQzIFAyCi0gTm90ZXM6IHRoZSBwbGF0ZXMgbXVzdCBiZSBwbGFjZWQgaW4gb3JkZXIhIQoKYGBge3J9CiMgR2VuZXJhdGUgc2VxdWVuY2luZyBjc3YKaWYgKEZBTFNFKSB7CmdlbmV3aXpfdGFibGUgPC0gdGliYmxlKFNhbXBsZSA9IDE6KDk2KjYpLCAKICAgICAgIGBETkEgTmFtZWAgPSBwYXN0ZTAocmVwKGMoIkIyX1Q3XzkzM19QMiIsICJCMl9UN180NDRfUDIiLCAiQzJfVDdfMTNBX1AyIiwgIkMyX1Q3XzEzQl9QMiIsICAiRF9UN183NV9QMiIsICJEX1Q3XzU1NDNfUDIiKSwgZWFjaCA9IDk2KSwgIl8iLCByZXAoMTo5NiwgNikpLCAKICAgICAgIGBMZW5ndGggKGJwKWAgPSAxMDAwLCBgQ29uY2VudHJhdGlvbiAobmcvdUwpYCA9IDAuODMsIFByaW1lciA9ICIyN0YiKQoKd3JpdGVfY3N2KGdlbmV3aXpfdGFibGUsIGhlcmU6OmhlcmUoIm91dHB1dC9wcm90b2NvbC90YWJfZmlnLzIwMjExMjAyX1Nhbmdlcl9zZXFfcHJlcC1nZW5ld2l6X3RhYmxlX0NZQy5jc3YiKSkKCn0KYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL0NBU0VVX3NpeHBsYXRlcy5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCgojIyBSYW5kb20gbmV0d29yaywgQ0FTRVUgYmF0Y2ggMQoKLSBHZW5ld2l6IHN1Ym1pc3N0aW9uIGNvZGU6IENhc2V1X1JOXzEKLSBQbGF0ZSBsYXlvdXQ6IFQzIEMgUDIKLSBEZXNjcmlwdGlvbjogc2FtcGxlcyAzLCA0LCA1LCAxMiwgMTMsIDI3LCAyOSwgMzMsIDczLCA4NSwgODYsIDkxLCBhbmQgOTQgKG9yZGVyIGJ5IGNvbHVtbiBpbiB0aGUgcGxhdGUgbGF5b3V0KSBhcnJpdmVkIEdlbmV3aXogZHJ5LCBzbyB0aGV5IGFyZSBub3QgcHJvY2Vzc2VkLgoKYGBge3J9CiMgSWYgd2lsbCB0YWtlIH4yIGhyIHRvIHJ1bgppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1yYW5kb21fbmV0d29ya19DQVNFVS0wMS1iYXRjaDEuUiIpCmBgYAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9STjEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDIKCi0gR2VuZXdpeiBzdWJtaXNzaW9uIGNvZGU6IENhc2V1X1JOXzIKLSBQbGF0ZSBsYXlvdXQ6IFQzIEMgUDIKLSBEZXNjcmlwdGlvbjogdGhpcyBwbGF0ZSBsYXlvdXQgY29udGFpbnMgdGhlIGlzb2xhdGVzIGZvciBhbGwgNCByYW5kb20gYXNzZW1ibGVkIGNvbW11bml0aWVzIAoKYGBge3J9CiMgSXQgdGFrZXMgfjMwIG1pbnMKaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkItcmFuZG9tX25ldHdvcmtfQ0FTRVUtMDItYmF0Y2gyLlIiKQpgYGAKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvQ0FTRVVfUk4yLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDMKCi0gR2VuZXdpeiBzdWJtaXNzdGlvbiBjb2RlOiBDYXNldV9STl8zCi0gUGxhdGUgbGF5b3V0OiAKICAgIC0gUDEgKFQwIEMgUDIpLCB0cmFja2luZyBudW1iZXIgMzAtMzMzNjQ5MTQzCiAgICAtIFAyIChUMCBBRCBQMiksIHRyYWNraW5nIG51bWJlciAzMC0zMzM2NDkzNjUKICAgIC0gUDMgKFQzIEFEIFAyKSwgdHJhY2tpbmcgbnVtYmVyIDMwLTMzMzY0OTUxNwotIERlc2NyaXB0aW9uOiBBRCBwbGF0ZXMgaGF2ZSB0aGUgaXNvbGF0ZXMgYXNzZW1ibGVkIGZyb20gdGhlIHNlbGYtYXNzZW1ibGVkIGNvbW11bml0aWVzIGJ1dCBkaWZmZXJlbnQgY29tbXVuaXRpZXMKCmBgYHtyfQojIEl0IHRha2VzIH4xLjUgaHIKaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkItcmFuZG9tX25ldHdvcmtfQ0FTRVUtMDMtYmF0Y2gzLlIiKQpgYGAKClVzZSBUMCBPRCBmcmVxdWVuY2llcwoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9DQVNFVV9STjMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKIyMgUmFuZG9tIG5ldHdvcmssIENBU0VVIGJhdGNoIDQKCi0gR2VuZXdpeiBzdWJtaXNzdGlvbiBjb2RlOiBDYXNldV9STl80Ci0gUGxhdGUgbGF5b3V0OiBUMyBCRCBQMwotIERlc2NyaXB0aW9uOiBUaGlzIHBsYXRlIGhhcyB0aGUgZnVsbCBBY3JBc3MyIChCKSBhbmQgaGFsZiBvZiBSYW5Bc3MyIChEKSBuZXR3b3JrLgoKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQi1yYW5kb21fbmV0d29ya19DQVNFVS0wNC1iYXRjaDQuUiIpCmBgYAoKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvQ0FTRVVfUk40LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCgojIDAyQyBwYWlyc19PRF9DRlUKCi0gRXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5CgotIERlcml2ZSBpc29sYXRlcycgJFxlcHNpbG9uJCBmcm9tIFQ4IGRhdGEgYW5kIGNhbGN1bGF0ZSB1bmNlcnRhdGludHkgdXNpbmcgZXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5CgotIENvbnZlcnQgVDAgT0QgZnJlcXVlbmN5ICRmXk8kIHRvIENGVSBmcmVxdWVuY3kgJGZeQyQgYW5kIGVzdGltYXRlIHRoZSB1bmNlcnRhaW50eSBpbiBjb252ZXJ0ZWQgQ0ZVIGZyZXF1ZW5jaWVzIGF0IFQ4LiBPdXRwdXQgYGRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3ZgCgojIyBHZW5lcmFsIGZvcm11bGEgb2YgZXJyb3IgcHJvcGFnYXRpb24KClRoaXMgc2VjdGlvbiBleHBsYWlucyB0aGUgZXJyb3IgcHJvcGFnYXRpb24gdGhlb3J5IHRvIGVzdGltYXRlIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgZXhwZXJpbWVudGFsIG1lYXN1cmVtZW50LiBUaGVyZSBhcmUgb25lIG9yIG1vcmUgcXVhbnRpdGllcyAkeCwgeSwgLi4uJCwgd2l0aCBjb3JyZXNwb25kaW5nIHVuY2VydGFpbnRpZXMgJFxkZWx0YSB4LCBcZGVsdGEgeSwgLi4uJCBhbmQgdGhhdCB3ZSB3aXNoIHRvIHVzZSB0aGUgbWVhc3VyZWQgdmFsdWVzIG9mIHggYW5kIHkgdG8gY2FsY3VsYXRlIHRoZSBxdWFudGl0eSBvZiByZWFsIGludGVyZXN0IHEuIFRoZXJlIGFyZSB0aHJlZSBwcm92aXNpb25hbCBydWxlczoKCjEuIFRoZSBzcXVhcmUtcm9vdCBydWxlIGZvciBjb3VudGluZyBleHBlcmltZW50cy4gVGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIGV2ZW50IGluIHRpbWUgVCBpcyAkdlxwbVxzcXJ0e3Z9JAoKMi4gVW5jZXJ0YWludHkgaW4gKipzdW1zIGFuZCBkaWZmZXJlbmNlcyoqLiBUaGUgY29tcHV0ZWQgbWVhbiB2YWx1ZSAkcT14K3krei0odSt3KSQuIElmIHRoZSB1bmNlcnRhaW50aWVzIGluIHgsIC4uLiwgdyBhcmUga25vd24gdG8gYmUgaW5kZXBlbmRlbnQgYW5kIHJhbmRvbSwgdGhlbiB0aGUgdW5jZXJ0YWludHkgaW4gdGhlIGNvbXB1dGVkIHZhbHVlIG9mIHEgaXMgdGhlIHF1YWRyYXRpYyBzdW0gJFxkZWx0YSBxID0gXHNxcnR7KFxkZWx0YSB4KV4yKyhcZGVsdGEgeSleMisoXGRlbHRhIHopXjIrKFxkZWx0YSB1KV4yKyhcZGVsdGEgdyleMn0kICwgSW4gYW55IGNhc2UsICRcZGVsdGEgcSQgaXMgbmV2ZXIgbGFyZ2VyIHRoYW4gdGhlaXIgb3JkaW5hcnkgc3VtICRcZGVsdGEgcSBcbGVxc2xhbnQgXGRlbHRhIHggKyBcZGVsdGEgeSsgXGRlbHRhIHogKyBcZGVsdGEgdSArIFxkZWx0YSB3JAoKMy4gVW5jZXJ0YWludHkgaW4gKipwcm9kdWN0IGFuZCBxdW90aWVudHMqKi4gJHE9XGZyYWN7eFx0aW1lcyB6fXt1XHRpbWVzIHd9JCwgdGhlbiB0aGUgZnJhY3Rpb25hbCB1bmNlcnRhaW50eSBpbiB0aGUgY29tcHV0ZWQgdmFsdWUgcSBpcyB0aGUgc3VtLiBJZiB0aGUgdW5jZXJ0YWludGllcyBpbiB4LCAuLi4sdyBhcmUgaW5kZXBlbmRlbnQgYW5kIHJhbmRvbSwgdGhlbiB0aGUgZnJhY3Rpb25hbCB1bmNlcnRhaW50eSBpbiBxIGlzIHRoZSBzdW0gaW4gcXVhZHJhdHVyZSBvZiB0aGUgb3JpZ2luYWwgdW5jZXJ0YWludGllcywgJFxmcmFje1xkZWx0YSBxfXtcbGVmdHxxXHJpZ2h0fH0gPSBcc3FydHsoXGZyYWN7XGRlbHRhIHh9e1xsZWZ0fHhccmlnaHR8fSleMiArIFxmcmFje1xkZWx0YSB5fXtcbGVmdHx5XHJpZ2h0fH0pXjIgK1xmcmFje1xkZWx0YSB6fXtcbGVmdHx6XHJpZ2h0fH0pXjIgK1xmcmFje1xkZWx0YSB1fXtcbGVmdHx1XHJpZ2h0fH0pXjIgKyBcZnJhY3tcZGVsdGEgd317XGxlZnR8d1xyaWdodHx9KV4yfSQuICRcZnJhY3tcZGVsdGEgcX17XGxlZnR8IHEgXHJpZ2h0fH0gXGxlcXNsYW50IFxmcmFje1xkZWx0YSB4fXtcbGVmdHwgeCBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB6fXtcbGVmdHwgeiBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB1fXtcbGVmdHwgdSBccmlnaHR8fSArIFxmcmFje1xkZWx0YSB3fXtcbGVmdHwgdyBccmlnaHR8fSQgCgpUYWtpbmcgdGhlc2UgdGhyZWUgcHJvdmlzaW9uYWwgcnVsZXMgdG9nZXRoZXIsIHRoZSBnZW5lcmFsIGZvcm11bGEgZm9yIGVycm9yIHByb3BhZ2F0aW9uIHRha2VzIHRoZSBmb2xsb3dpbmcgZm9ybS4gQXNzdW1lIHRoZSBjb21wdXRlZCBxdWFudGl0eSBpcyBhIGZ1bmN0aW9uIG9mICR4XzEsIHhfMiwgLi4uLCB4X24kLCB0aGUgdW5jZXJ0YWludHkgaW4gcSBpcyAkJFxkZWx0YSBxPSBcc3FydHsoXHN1bXtcZnJhY3tccGFydGlhbCBxfXtccGFydGlhbCB4X2l9fVxkZWx0YSB4X2kpXjJ9JCQgCgoKCiMjIFVuY2VydGFpbnR5IGluIGVwc2lsb24gCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkMtcGFpcnNfT0RfQ0ZVLTAxLWVwc2lsb25fdW5jZXJ0YWludHkuUiIpCmBgYAoKClRoZSB1bmNlcnRhaW50aWVzIGluIGVhY2ggaXNvbGF0ZScgZXBzaWxvbiAkXGVwc2lsb25fQSA9IFxmcmFje09EX0EgREZfQSB2X0F9e0NGVV9BfSQgY29tZXMgZnJvbSBmb3VyIHBhcnRzOgoKMS4gJERGJDogRGlsdXRpb24gZmFjdG9ycy4gVGhlIHVuY2VydGFpbnR5IGNvbWVzIGZyb20gdGhlIHBpcGV0dGluZyBpbiBzZXJpYWwgZGlsdXRpb24sIHdoaWNoIGlzIGNhbGNhdWx0ZWQgYmVsb3cuCjIuICR2JDogUGxhdGluZyB2b2x1bWVzLiBUaGUgc3lzdGVtYXRpYyBlcnJvciBmb3IgUDIwIHNldCBhdCAyMCB1TCBpcyAwLjQgdUwuCjMuICRDRlUkOiBDRlUgY291bnRzLiBUaGUgdW5jZXJ0YWludHkgaW4gQ0ZVIGZvbGxvd3MgcG9pc3NvbiBkaXN0cmlidXRpb24sIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHZhcmlhbmNlIGlzIHRoZSBzYW1lIGFzIHRoZSBtZWFuIChtZWFzdXJlZCBDRlUpLiBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzICRcc3FydHtDRlV9JC4KNC4gJE9EJDogT0QgbWVhc3VyZW1lbnQuIFRoZSB1bmNlcnRhaW50eSBpbiBtZWFzdXJpbmcgT0QgaW4gcGxhdGUgcmVhZGVyLCB3aGljaCBpcyBhc3N1bWVkIHRvIGJlIDAuMDAxLgoKCioqRGlsdXRpb24gZmFjdG9yKioKClRoZSB1bmNlcnRhaW50eSBpbiBkaWx1dGlvbiBmYWN0b3IgY29tZXMgZnJvbSB0aGUgcGlwZXR0aW5nIHN0ZXBzIGluIHNlcmlhbCBkaWx1dGlvbiwgd2hpY2ggaW5jbHVkZSB0d28gcGlwZXR0aW5nIHZvbHVtZXM6CgoxLiBgVjFgOiBzZXJpYWwgZGlzcGVuc2luZyAxMCB1TCBvZiBkaWx1dGVkIHNvbHV0aW9uIHVzaW5nIG1QMjAuIEl0IGhhcyB1bmNlcnRhaW50eSBgRXJyb3JWMWAgMiB1TC4KMi4gYFYyYDogZGlzcGVuc2UgOTAgdUwgb2YgUEJTIHVzaW5nIG1QMjAwLiBJdCBoYXMgdW5jZXJ0YWludHkgYEVycm9yVjJgIDAuNCB1TC4KCkZvciBkaWx1dGlvbiBmYWN0b3IgJDEwXntufSQsIGl0IGhhcyB0aGUgdGhlIG1lYW4gJChcZnJhY3tWXzF9e1ZfMStWXzJ9KV5uJC4gVG8gb2J0YWluIHRoZSB1bmNlcnRhaW50eSBpbiB0aGUgbWVhc3VyZWQgbWVhbiwgZmlyc3Qgd2UgY2FsdWN1bGF0ZSB0aGUgcGFydGlhbCBkZXJpdmF0aXZlcyAkXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMX0kIGFuZCAkXGZyYWN7XHBhcnRpYWwgREZ9e1xwYXJ0aWFsIFZfMn0kLiBUaGVuIHRoZSB1bmNlcnRhaW50eSAkXGRlbHRhIERGID0gXHNxcnR7KFxmcmFje1xwYXJ0aWFsIERGfXtccGFydGlhbCBWXzF9XGRlbHRhIFZfMSleMiArIChcZnJhY3tccGFydGlhbCBERn17XHBhcnRpYWwgVl8yfVxkZWx0YSBWXzIpXjJ9JAoKCmBgYHtyfQpkaWx1dGlvbl9mYWN0b3IgPC0gdGliYmxlKG4gPSBjKDQsIDUpLCBWMSA9IDEwLCBWMiA9IDkwLCBFcnJvclYxID0gMC40LCBFcnJvclYyID0gMikgJT4lCiAgbXV0YXRlKFBhcnRpYWxWMSA9IG4gKiBWMV4obi0xKSAqIFYyIC8gKFYxK1YyKV4obisxKSwgIy1uKihWMStWMileKG4tMSkqVjIvKFYxXihuKzEpKSwKICAgICAgICAgUGFydGlhbFYyID0gLW4gKiBWMV4obi0xKSAvIChWMStWMileKG4rMSksICNuKihWMStWMileKG4tMSkvKFYxXm4pLAogICAgICAgICBERiA9IChWMS8oVjErVjIpKV5uLAogICAgICAgICBFcnJvckRGID0gc3FydCgoUGFydGlhbFYxKkVycm9yVjEpXjIgKyAoUGFydGlhbFYyKkVycm9yVjIpXjIpKQoKZGlsdXRpb25fZmFjdG9yCmBgYAoKCkJ5IHVzaW5nIGVycm9yIHByb3BhZ2F0aW9uIHRoZXJveSwgdGhlIHVuY2VydGFpbnR5IGluIGlzb2xhdGVzIGVwc2lsb24gaGFzIHRoZSBmb3JtIAoKJCRcZGVsdGEgXGVwc2lsb24gPSBcc3FydHsoXGZyYWN7XHBhcnRpYWwgIFxlcHNpbG9ufXtccGFydGlhbCBERn1cZGVsdGEgREYpXjIgKyhcZnJhY3tccGFydGlhbCAgXGVwc2lsb259e1xwYXJ0aWFsIENGVX1cZGVsdGEgQ0ZVKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgT0R9XGRlbHRhIE9EKV4yICsgKFxmcmFje1xwYXJ0aWFsICBcZXBzaWxvbn17XHBhcnRpYWwgVn1cZGVsdGEgVileMn0kJAoKCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5IDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9pc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKaXNvbGF0ZXNfZXBzaWxvbl91bmNlcnRhaW50eQpgYGAKClRoZXJlIGFyZSA3IGlzb2xhdGVzIHRoYXQgaGF2ZSBlaXRoZXIgMCBDRlUgb3IgbmVnYXRpdmUgT0QgdmFsdWUsIHNvIHRoZXkgZG9uJ3QgaGF2ZSBlcHNpbG9uIHZhbHVlcy4KCmBgYHtyfQppc29sYXRlc19lcHNpbG9uX3VuY2VydGFpbnR5ICU+JQogIGZpbHRlcihpcy5uYShFcHNpbG9uKSkKYGBgCgojIyBDb252ZXJ0IFQwIE9EIGZyZXF1ZW5jaWVzIHRvIENGVSBmcmVxdWVuY2llcwoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJDLXBhaXJzX09EX0NGVS0wMi1DRlVfZnJlcXVlbmN5LlIiKQpgYGAKClRoZSBvdXRjb21lIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIHdlcmUgZGV0ZXJtaW5lZCBieSBjb21wYXJpbmcgdGhlIGZyZXF1ZW5jeSBjaGFuZ2VzIGJldHdlZW4gVDAgYW5kIFQ4LiBUaGUgVDggZnJlcXVlbmNpZXMgd2VyZSBkZXRlcm1pbmVkIGJ5IHBsYXRpbmcgdGhlIG1hdHVyZSBtZWRpYSBvbiByaWNoIGFnYXIgbWVkaWEgb24gd2hpY2ggdGhlIGNvbG9uaWVzIHdlcmUgY291bnRlZCwgd2hlcmVhcyBUMCBmcmVxdWVuY2llcyB3ZXJlIHNldCB0byA5NS81LCA1MC81MCBhbmQgNS85NSBieSBtaXhpbmcgdHdvIGlzb2xhdGUgaW5vY3VsYSB3aXRoIGVxdWFsIE9ELiAgSW4gdGhpcyBzZWN0aW9uLCBJIHdpbGwgdXNlIHRoZSBPRC1DRlUgY29udmVyc2lvbiBjb2VmZmljaWVudCAkXGVwc2lsb24kIGRlcml2ZWQgZnJvbSBUOCBpc29sYXRlIGRhdGEgdG8gY29udmVydCBUMCBPRCBmcmVxdWVuY2llcyBpbnRvIENGVSBmcmVxdWVuY2llcy4gSW4gc3BlY2lmaWMsIHRoZSBDRlUgZnJlcXVlbmN5IG9mIGlzb2xhdGUgMSAkZl5DXzEkIG9mIGEgcGFpciBjYW4gYmUgZGVyaXZlZCBmcm9tIE9EIGZyZXF1ZW5jaWVzIG9mIGlzb2xhdGUgMSBhbmQgMiAkZl5PXzEgLGZeT18yJCwgd2hpY2ggaGF2ZSB0aGUgcmVsYXRpb25zaGlwIGJlbG93LiAKCiRmXkNfMSA9IFxmcmFje2Zeb18xXGVwc2lsb25fMURGdn17Zl5vXzFcZXBzaWxvbl8xREZ2ICsgZl5vXzJcZXBzaWxvbl8yREZ2fT1cZnJhY3tmXm9fMVxlcHNpbG9uXzF9e2Zeb18xXGVwc2lsb25fMSArIGZeb18yXGVwc2lsb25fMn0kCgp3aGVyZSAkXGVwc2lsb24kIG9mIGVhY2ggaXNvbGF0ZSB3YXMgcHJlLWNhbGN1bGF0ZWQgZnJvbSBUOCBkYXRhc2V0LiBERiBhbmQgdiBhcmUgdGhlIHNhbWUgaW4gY29udmVyc2lvbi4KCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfQ0ZVX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgojIyBVbmNlcnRhaW50eSBpbiBUMCBDRlUgZnJlcXVlbmNpZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyQy1wYWlyc19PRF9DRlUtMDMtQ0ZVX2ZyZXF1ZW5jeV91bmNlcnRhaW50eS5SIikKYGBgCgpXcml0ZSBDRlUgZnJlcXVlbmNpZXMgdG8gYGRhdGEvdGVtcC9wYWlyc19DRlVfZnJlcV91bmNlcnRhaW50eS5jc3ZgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKIyAwMkQgZGV0ZXJtaW5lIHBhaXJ3aXNlIGludGVyYWN0aW9uCgojIyBDb21iaW5lIG91dGNvbWVzIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIGZyb20gQ0ZVIGNvdW50cyBhbmQgQ0FTRVUKClJhdyBkYXRhIChlLmcuLCBDRlUgY291bnRzIGFuZCBDQVNFVSBTYW5nZXIgc2VxdWVuY2VzKSBhcmUgcHJvY2Vzc2VkIGFuZCBnZW5lcmF0ZWQgaW50byB0ZW1wb3JhcnkgcmVzdWx0IGNzdjoKCjEuIGAwMkItQ0FTRVVfc2FuZ2VyX3NlcWAgcmVhZHMgQ0FTRVUgcmF3IGRhdGEgYW5kIG91dHB1dHMgYHRlbXAvQ0FTRVVfcGlsb3QyLmNzdmAgYW5kIGB0ZW1wL0NBU0VVX3BpbG90My5jc3ZgLiBCb3RoIGZpbGVzIGFyZSBDQVNFVSBwcmVkaWN0ZWQgVDggZnJlcXVlbmNpZXMuCgoyLiBgMDJDLXBhaXJzX09EX0NGVWAgcmVhZHMgcGFpcl9jb21wZXRpdGlvbiBhbmQgZGlsdXRpb24gZmFjdG9yIGRhdGEsIGFuZCBpdCBvdXRwdXRzIGB0ZW1wL3BhaXJzX0NGVV9mcmVxX3VuY2VydGFpbnR5LmNzdmAsIHdoaWNoIGhhcyB0aGUgVDAgT0QtY29udmVydGVkIENGVSBmcmVxdWVuY2llcyBhbmQgVDggQ0ZVIGZyZXF1ZW5jaWVzIHdpdGggdW5jZXJ0YWludGllcy4KCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkQtZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLTAxLWNvbWJpbmVfQ0ZVX0NBU0VVX3Jlc3VsdC5SIikKYGBgCgpUaGUgc2NyaXB0IGluIHRoaXMgc2VjdGlvbiByZXR1cm5zIGEgZGF0YS5mcmFtZSBgcGFpcnNfZnJlcWAgdGhhdCBoYXMgdGhlIGZvbGxvd2luZyB2YXJpYWJsZXM6CgotIGBDb21tdW5pdHlgCi0gYElzb2xhdGUxYCBhbmQgYElzb2xhdGUyYDogaW5kaWNlcyBvZiBpc29sYXRlcyB3aXRoaW4gYSBjb21tdW5pdHkuIFRoZSBudW1iZXIgb2YgaXNvbGF0ZTEgaXMgYWx3YXlzIHNtYWxsZXIgdGhhbiBpc29sYXRlMgotIGBJc29sYXRlMUluaXRpYWxPREZyZXFgIGFuZCBgSXNvbGF0ZTJJbml0aWFsT0RGcmVxYDogNSwgNTAgb3IgOTUuIFRoZSBpbml0aWFsIE9EIGZyZXF1ZW5jaWVzIG9mIGlzb2xhdGVzIGF0IFQwLiBUaGlzIHR3byBzZXJ2ZSBhcyBkaXNjcmV0ZSBncm91cGluZyB2YXJpYWJsZXMuCi0gYFRpbWVgOiBUMCBvciBUOC4KLSBgSXNvbGF0ZTFNZWFzdXJlZEZyZXFgOiB0aGUgbWVhc3VyZWQgZnJlcXVlbmN5IG9kIGlzb2xhdGUxIGluIHRoZSBwYWlyLiAKLSBgRXJyb3JJc29sYXRlMU1lYXN1cmVkRnJlcWA6IHRoZSB1bmNlcnRhaW50eSBvZiBgSXNvbGF0ZTFNZWFzdXJlZEZyZXFgLgotIGBSYXdEYXRhVHlwZWA6IE9ELCBPRHRvQ0ZVLCBDRlUsIFNhbmdlciAoQ0FTRVUpLiBUaGUgcmF3IGRhdGEgdHlwZSBpbiB3aGljaCB0aGUgaXNvbGF0ZSBmcmVxdWVuY2llcyB3ZXJlIG1lYXN1cmVkLgotIGBDb250YW1pbmF0aW9uYDogbG9naWNhbC4gVGhlcmUgYXJlIGNvbnRhbWluYXRpb24gaW4gdGhyZWUgcGFpcnMgYXQgVDggcGxhdGVzLgoKMTg2eDN4Mj0xMTE2IHBhaXItZnJlcSBhdCB0d28gdGltZSBwb2ludHMgZm9yIHRoZSBzZWxmLWFzc2VtYmxlZCBjb21tdW5pdHkgbmV0d29ya3MuCgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKCgoKCiMjIERldGVybWluZSBwYWlyd2lzZSBpbnRlcmFjdGlvbnMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRC1kZXRlcm1pbmVfcGFpcndpc2VfaW50ZXJhY3Rpb24tMDItZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLlIiKQpgYGAKClRhYmxlIG9mIGFsbCAyNyArIDQgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGZpdG5lc3MgZnVuY3Rpb24gYW5kIHRoZWlyIGludGVyYWN0aW9uIHR5cGVzIAoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ludGVyYWN0aW9uX3RhYmxlLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKVGFibGUgb2YgaW50ZXJhY3Rpb24gdHlwZXMKCmBgYHtyfQpwYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzIDwtIHJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvdGVtcC9wYWlyc19pbnRlcmFjdGlvbl9maXRuZXNzLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKcGFpcnNfaW50ZXJhY3Rpb25fZml0bmVzcyAlPiUKICBncm91cF9ieShTZXQsIEludGVyYWN0aW9uVHlwZSkgJT4lCiAgc3VtbWFyaXplKENvdW50ID0gbigpLCAuZ3JvdXBzID0gImtlZXAiKSAKYGBgCgojIyBJc29sYXRlIHRvdXJuYW1lbnQKCgpgYGB7cn0KaWYgKHJ1bl9zY3JpcHRzKSBzb3VyY2UoInNjcmlwdC8wMkQtZGV0ZXJtaW5lX3BhaXJ3aXNlX2ludGVyYWN0aW9uLTAzLWlzb2xhdGVfdG91cm5hbWVudC5SIikKYGBgCgpUb3VybmFtZW50IHJhbmtzIG9mIGVhY2ggaXNvbGF0ZS4gTm90ZSB0aGF0IEkgY29uc2lkZXIgbmV0dXJhbGl0eSBhbmQgYmlzdGFiaWxpdHkgYXMgZHJhdyBpbiB0aGUgdG91cm5hbWVudC4KCi0gYFNjb3JlYDogdGhlIGNvbXBldGl0aXZlIHNjb3JlcyBvZiBpc29sYXRlLiBUaGlzIHNjb3JlIGlzIGNvbXB1dGVkIGJ5IHRoZSBmb3JtdWxhOiBudW1iZXIgb2Ygd2lucyAtIG51bWJlciBvZiBsb3NlcyArIDAgKiBudW1iZXIgb2YgZHJhd3MuIAotIGBHYW1lYDogbnVtYmVyIG9mIHBhaXJ3aXNlIGNvbXBldGl0aW9uIHRoZSBpc29sYXRlIGhhcyBwbGF5ZWQuIFRoZSBudW1iZXIgb2YgZ2FtZXMgYW4gaXNvbGF0ZSBwbGF0ZWQgd2l0aGluIGEgY29tbXVuaXR5IHNob3VsZCBiZSBjb21tdW5pdHkgc2l6ZSBtaW51cyBvbmUuIAotIGBSYW5rYDogdGhlIHJhbmtzIGJhc2VkIG9uIGBTY29yZWAuIFRoZSByYW5rcyByYW5nZSBmcm9tIDEgdG8gdGhlIGZvY2FsIGNvbW11bml0eSBzaXplLiBJc29sYXRlcyB3aXRoIHRoZSBzYW1lIHNjb3JlcyBpbiBhIGNvbW11bml0eSBhcmUgZ2l2ZW4gdGhlIHNhbWUgcmFuay4KLSBgUGxvdFJhbmtgOiBjb250aW51b3VzIHJhbmsgZm9yIHBsb3R0aW5nIGNvbnZlbmllbmNlLgoKCiMgMDJFIGNvbXBldGl0aW9uIHBoeWxvZ2VueQoKLSBDb3JyZWxhdGUgY29tcGV0aXRpb24gcmVzdWx0IHdpdGggcGh5bG9nZW5ldGljIGRpc3RhbmNlCgotIE1lYXN1cmUgdGhlIHBhaXJ3aXNlIHBoeWxvZ2VuZXRpYyBkaXN0YW5jZXMgYnkgZGlmZmVyZW5jZSBpbiAxNlMgYmFzZSBwYWlycyBgcGFpcnNfdGF4b25vbXlgCiAgICAtIENvYXJzZS1ncmFpbmVkIHRheG9ub215IChGYW1pbHkgYW5kIEdlbnVzKQogICAgLSBDb21wdXRlIHRoZSBwYWlyd2lzZSBzZXF1ZW5jZSBkaWZmZXJlbmNlcyB1c2luZyBgQmlvc3RyaW5nOjpwYWlyd2lzZUFsaWdubWVudCgpYCAKICAgIC0gQ29tcHV0ZSBwYWlyd2lzZSB0cmVlIGRpc3RhbmNlIHVzaW5nIGBhcGU6OmNvcGhlbmV0aWMucGh5bG8oKWAgb24gYnVpbHQgdHJlZS4gVHJ5IG91dCBkaWZmZXJlbnQgdHJlZSBidWlsZGluZyBtZXRob2RzCgoKIyMgSXNvbGF0ZXMnIFJEUCB0YXhvbm9teQoKYGBge3J9CmlmIChydW5fc2NyaXB0cykgc291cmNlKCJzY3JpcHQvMDJFLWNvbXBldGl0aW9uX3BoeWxvZ2VueS0wMS1wYWlyc190YXhvbm9teS5SIikKYGBgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS90ZW1wL3BhaXJzX3RheG9ub215LmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCiMjIElzb2xhdGVzJyAxNlMgc2VxdWVuY2UgZGlmZmVyZW5jZQoKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyRS1jb21wZXRpdGlvbl9waHlsb2dlbnktMDItcGFpcnNfMTZTLlIiKQpgYGAKCmBgYHtyfQpyZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL3RlbXAvcGFpcnNfMTZTLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgoKCgojIFN1bW1hcnkKCiMjIFJlYWQgYW5kIGNvbWJpbmUgcGFpcnMgZGF0YSAKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAxLXJlYWRfZGF0YS5SIikKYGBgCgoxODYgcGFpcnMgb2Ygc2VsZi1hc3NlbWJsZWQgY29tbXVuaXRpZXMgYW5kIDExMiBwYWlyIGZyb20gYWNyb3NzLWNvbW11bml0eSBhbmQgcmFuZG9tIG5ldHdvcmtzCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnMuY3N2IiwgY29sX3R5cGVzID0gY29scygpKQpgYGAKClBhaXJzIHdpdGggdGhyZWUgaW5pdGlhbCBmcmVxdWVuY2llcyBhbmQgdGhyZWUuIDE4NngzeDI9MTExNgoKYGBge3J9CnJlYWRfY3N2KCJ+L0Ryb3Bib3gvbGFiL2VtZXJnZW50LWNvZXhpc3RlbmNlL2RhdGEvb3V0cHV0L3BhaXJzX2ZyZXEuY3N2IiwgY29sX3R5cGVzID0gY29scygpKSAlPiUKICAgIGZpbHRlcihTZXQgPT0gIkNGVWFuZENBU0VVIikKYGBgCgpwYWlyc19tZXRhIGNvbnRhaW5zIHRoZSBncm93dGggdHJhaXRzIG9mIGlzb2xhdGVzLiBOb3RlIHRoYXQgdGhlIG9yZGVyIG9mIElzb2xhdGUxIGFuZCBJc29sYXRlMiBpbiBzb21lIHBhaXJzIGFyZSBmbGlwcGVkIHN1Y2ggdGhhdCBJc29sYXRlMSBpcyBhbHdheXMgdGhlIGRvbWluYW50IHN0cmFpbiBhbmQgSXNvbGF0ZSAyIGlzIHRoZSBzdWJkb21haW50IG9uZS4gRG9taW5hbnQgc3RyYWluIGlzIHRoZSB3aW5uZXIgaW4gZXhjbHVzaW9uIHBhaXJzLCBhbmQgdGhlIG1vcmUgYWJ1bmRhbnQgc3RyYWluICg1MDo1MCB0cmVhdG1lbnQpIGluIGNvZXhpc3RlbmNlIHBhaXJzLgoKYGBge3J9CmlmIChGQUxTRSkgcGFpcnNfbWV0YSA8LSByZWFkX2Nzdigifi9Ecm9wYm94L2xhYi9lbWVyZ2VudC1jb2V4aXN0ZW5jZS9kYXRhL291dHB1dC9wYWlyc19tZXRhLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoKSkKYGBgCgpFeGFtcGxlIG91dGNvbWUgdHlwZXMKCmBgYHtyfQppZiAocnVuX3NjcmlwdHMpIHNvdXJjZSgic2NyaXB0LzAyLXBhaXJzLTAyLW91dGNvbWVfdHlwZXMuUiIpCmBgYAoKQ29hcnNlLWdyYWluZWQgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnNfZXhhbXBsZV9vdXRjb21lcy5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYApGaW5lLWdyYWluZWQgCgpgYGB7cn0KcmVhZF9jc3YoIn4vRHJvcGJveC9sYWIvZW1lcmdlbnQtY29leGlzdGVuY2UvZGF0YS9vdXRwdXQvcGFpcnNfZXhhbXBsZV9vdXRjb21lc19maW5lci5jc3YiLCBjb2xfdHlwZXMgPSBjb2xzKCkpCmBgYAoKCgoKCgo=